package lib.bone.flow.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Validator;
import lib.bone.common.constant.ResponseCodeConst;
import lib.bone.common.core.domain.ResponseDTO;
import lib.bone.common.utils.JsonUtil;
import lib.bone.flow.constant.FlowNodeTypeConst;
import lib.bone.flow.constant.FlowTaskStatusConst;
import lib.bone.flow.constant.FlowWorkStatusConst;
import lib.bone.flow.domain.dto.FlowParam;
import lib.bone.flow.domain.entity.FlowDefine;
import lib.bone.flow.domain.entity.FlowTask;
import lib.bone.flow.domain.entity.FlowWork;
import lib.bone.flow.domain.model.BaseModel;
import lib.bone.flow.domain.model.FlowModel;
import lib.bone.flow.domain.model.StartModel;
import lib.bone.flow.domain.model.TaskModel;
import lib.bone.flow.module.parser.FlowNodeParser;
import lib.bone.flow.module.processor.FlowNodeProcessorCtl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author: kindear
 */
@Slf4j
@Service
public class FlowWorkCtl {


    @Autowired
    FlowNodeParser flowNodeParser;

    @Autowired
    FlowDefineService flowDefineService;

    @Autowired
    FlowWorkService flowWorkService;

    @Autowired
    FlowTaskService flowTaskService;

    @Autowired
    FlowNodeProcessorCtl flowNodeProcessorCtl;

//    @Async("taskExecutor")
    public ResponseDTO<FlowWork> startProcess(String flowDefineCode, String operator, FlowParam param) {
        log.info("[async]异步启动流程");
        Optional<FlowDefine> defineOp = flowDefineService.getByDefineCode(flowDefineCode);
        if(!defineOp.isPresent()){
            return ResponseDTO.wrap(ResponseCodeConst.NOT_FOUND);
        }
        /**
         * 设定操作者ID
         */
        if(Validator.isNotEmpty(operator)){
            param.setOperator(operator);
        }
        /**
         * 获取流程定义
         */
        FlowDefine flowDefine = defineOp.get();
        FlowModel flowModel = null;
        /**
         * 流程解析
         */
        try {
            flowModel = flowNodeParser.parser(flowDefine.getFlowDefine());
        }catch (Exception e){
            return ResponseDTO.wrap(ResponseCodeConst.SYSTEM_ERROR,"流程解析异常");
        }
        /**
         * 获取开始节点
         */
        StartModel startModel = flowModel.getStartModel();
        /**
         * 获取当前时间
         */
        Date now = DateUtil.date();
        /**
         * 新建一个流程实例
         */
        FlowWork flowWork = new FlowWork();
        //设置流程为非锁定状态
        flowWork.setLocked(0);
        flowWork.setCurrentNodeId(startModel.getId());
        flowWork.setNextNodeId(startModel.getNextNodeId());
        flowWork.setFlowName(flowDefine.getFlowName());
        flowWork.setFlowDefine(flowDefine.getFlowDefine());
        flowWork.setFlowDefineCode(flowDefine.getFlowDefineCode());
        flowWork.setLastOperator(operator);
        //设置流程发起人 -- 即开始流程的人
        flowWork.setInitiator(operator);
        //设置流程实例流转状态为进行中
        flowWork.setFlowWorkStatus(FlowWorkStatusConst.IN_PROGRESS);
        //设置流程实例状态为 正常
        flowWork.setStatus(1);
        flowWork.setFlowParam(JsonUtil.obj2String(param));
        //设置flowParam参数
        flowWork.setServiceId(param.getServiceId());
        flowWork.setServiceType(param.getServiceType());
        flowWork.setServiceName(param.getServiceName());
        /**
         * 写入数据库
         */
        FlowWork execRes = flowWorkService.saveOne(flowWork);
        /**
         * 执行开始模型
         */
        flowNodeProcessorCtl.process(execRes,flowModel,startModel,param);
        /**
         * 返回执行结果
         */
        return ResponseDTO.succData(execRes);
    }

    /**
     * 完成TASK
     * @param flowTaskId
     * @param operator
     * @param param
     * @return
     */
    public ResponseDTO completeTask(String flowTaskId, String operator, FlowParam param) {

        Optional<FlowTask> taskOp = flowTaskService.getById(flowTaskId);
        if (!taskOp.isPresent()){
            return ResponseDTO.wrap(ResponseCodeConst.NOT_FOUND,"无对应TASK");
        }
        FlowTask task = taskOp.get();
//        if (task.getServiceType().equals("论文")){
//
//            List<FlowWork> flowWorkList = flowWorkService.getPaperNumber("paper-check-01",task.getInitiator());
//            List<FlowWork> list = new ArrayList<>();
//            //通过的或者进行中的才会占用一次机会
//            for (FlowWork flowWork:flowWorkList){
//                if(flowWork.getFlowWorkStatus().equals(FlowWorkStatusConst.FINISHED)){
//                    list.add(flowWork);
//                }
//            }
//            if (list.size()>=3){
//                return ResponseDTO.succData(ResponseCodeConst.FORBIDDEN,"该教师本考核期内计算工作量的论文已达三篇的上限，无法继续通过！");
//            }
//        }
        // 如果没有传 flowParam ，继续沿用
        if (Validator.isEmpty(param)){
            param = JsonUtil.string2Obj(task.getFlowParam(),FlowParam.class);
        }
        // 非空赋值
        if (Validator.isNotEmpty(operator)){
            assert param != null;
            param.setOperator(operator);
        }
        if (task.getStatus().equals(0)){
            return ResponseDTO.wrap(ResponseCodeConst.FORBIDDEN,"流程任务已关闭");
        }
        if (!task.getTaskStatus().equals(FlowTaskStatusConst.CREATED)){
            return ResponseDTO.wrap(ResponseCodeConst.FORBIDDEN,"非进行态流程任务");
        }
        // 判断操作者是否在操作的列表中
        if (!task.getActUserId().equals(operator)){
            return ResponseDTO.wrap(ResponseCodeConst.UNAUTHORIZED,"该用户无权限操作");
        }
        // 获取流程实例
        Optional<FlowWork> workOp = flowWorkService.getById(task.getFlowWorkId());
        if (!workOp.isPresent()){
            return ResponseDTO.wrap(ResponseCodeConst.NOT_FOUND,"流程实例不存在");
        }
        FlowWork flowWork = workOp.get();
        if (flowWork.getStatus().equals(0)){
            return ResponseDTO.wrap(ResponseCodeConst.FORBIDDEN,"流程实例被挂起，无法执行");
        }
        // 2022-4-12 锁定流程实例
        flowWork.setLocked(1);
        flowWorkService.updateWork(flowWork);

        // 流程内容解析
        FlowModel flowModel = null;
        try {
            flowModel = flowNodeParser.parser(flowWork.getFlowDefine());
        } catch (IOException e) {
            e.printStackTrace();
            return ResponseDTO.wrap(ResponseCodeConst.SYSTEM_ERROR,"流程解析异常");
        }
        // 获取TASK 节点 performType
        BaseModel currentNodeModel = flowModel.getNodeModel(task.getFlowNodeId());
        // 获取next节点
        BaseModel nextNodeModel = flowModel.getNodeModel(currentNodeModel.getNextNodeId());
        TaskModel currentTaskModel = null;
        if (currentNodeModel.getNodeType().equals(FlowNodeTypeConst.TASK_NODE)) {
            currentTaskModel = (TaskModel) currentNodeModel;
        }
        if (Validator.isEmpty(currentTaskModel)){
            return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM,"非TASK节点");
        }
        log.info("阶段审核模式为:{}",currentTaskModel.getPerformType());
        assert currentTaskModel != null;
        if (currentTaskModel.getPerformType().equals("ANY") || currentTaskModel.getPerformType().equals("RACE")){
            // 如果是竞争机制 -- 获取全部分配的列表
            List<FlowTask> tasks = flowTaskService.getByFlowWorkIdAndFlowNodeId(flowWork.getId(),currentNodeModel.getId());
            FlowParam finalParam = param;
            tasks = tasks.stream().map(ele->{
                ele.setTaskStatus(FlowTaskStatusConst.FINISHED);
                ele.setFinishTime(DateUtil.date());
                ele.setOperator(operator);
                ele.setFlowParam(JsonUtil.obj2String(finalParam));
                return ele;
            }).collect(Collectors.toList());
            // 更新记录 -- List
            flowTaskService.saveList(tasks);
            // 如果满足，则进行下一步
            flowNodeProcessorCtl.process(flowWork,flowModel,nextNodeModel,param);
        }else if (currentTaskModel.getPerformType().equals("ALL")){
            task.setTaskStatus(FlowTaskStatusConst.FINISHED);
            task.setFinishTime(DateUtil.date());
            task.setOperator(operator);
            //重新赋值 flowParam
            task.setFlowParam(JsonUtil.obj2String(param));
            flowTaskService.saveOne(task);
            // 如果满足，则进行下一步
            List<FlowTask> tasks = flowTaskService.getByFlowWorkIdAndFlowNodeId(flowWork.getId(),currentNodeModel.getId());
            int count = 0;
            log.info("task-size:{}",tasks.size());

            for (FlowTask ele:tasks){
                if (ele.getTaskStatus().equals(FlowTaskStatusConst.FINISHED))
                    count++;
            }
            log.info("count:{}",count);
            if (count == tasks.size()){
                flowNodeProcessorCtl.process(flowWork,flowModel,nextNodeModel,param);
            }

        }


        return ResponseDTO.succMsg("完成TASK!");
    }


    /**
     * 驳回任务
     * @param flowTaskId
     * @param operator
     * @param flowParam
     * @return
     */
    public ResponseDTO rejectTask(String flowTaskId, String operator, FlowParam flowParam) {

        Optional<FlowTask> taskOp = flowTaskService.getById(flowTaskId);
        if (!taskOp.isPresent()){
            return ResponseDTO.wrap(ResponseCodeConst.NOT_FOUND,"无对应TASK");
        }
        FlowTask task = taskOp.get();
        // 流程任务已关闭则无法访问
        if (task.getStatus().equals(0)){
            return ResponseDTO.wrap(ResponseCodeConst.FORBIDDEN,"流程任务已关闭");
        }
        // 非进行中流程无法操作
        if (!task.getTaskStatus().equals(FlowTaskStatusConst.CREATED)){
            return ResponseDTO.wrap(ResponseCodeConst.FORBIDDEN,"非进行态流程任务");
        }
        // 判断操作者是否在操作的列表中
        if (!task.getActUserId().equals(operator)){
            return ResponseDTO.wrap(ResponseCodeConst.UNAUTHORIZED,"该用户无权限操作");
        }

        // 获取流程实例
        Optional<FlowWork> workOp = flowWorkService.getById(task.getFlowWorkId());
        if (!workOp.isPresent()){
            return ResponseDTO.wrap(ResponseCodeConst.NOT_FOUND,"流程实例不存在");
        }
        FlowWork flowWork = workOp.get();
        // 4-12 锁定流程实例
        flowWork.setLocked(1);
        if (flowWork.getStatus().equals(0)){
            return ResponseDTO.wrap(ResponseCodeConst.FORBIDDEN,"流程实例被挂起，无法执行");
        }
        FlowModel flowModel = null;
        try {
            flowModel = flowNodeParser.parser(flowWork.getFlowDefine());
        } catch (IOException e) {
            e.printStackTrace();
            return ResponseDTO.wrap(ResponseCodeConst.SYSTEM_ERROR,"流程解析异常");
        }
        // 获取TASK 节点 performType
        BaseModel currentNodeModel = flowModel.getNodeModel(task.getFlowNodeId());
        // 获取next节点
        //BaseModel nextNodeModel = flowModel.getNodeModel(currentNodeModel.getNextNodeId());
        TaskModel currentTaskModel = null;
        if (currentNodeModel.getNodeType().equals(FlowNodeTypeConst.TASK_NODE)) {
            currentTaskModel = (TaskModel) currentNodeModel;
        }
        if (Validator.isEmpty(currentTaskModel)){
            return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM,"非TASK节点");
        }
        // 查询列表 -- 并且修改状态为 REJECT
        List<FlowTask> tasks = flowTaskService.getByFlowWorkIdAndFlowNodeId(flowWork.getId(),currentNodeModel.getId());
      //  FlowParam finalParam = flowParam;
        tasks = tasks.stream().peek(ele->{
            ele.setTaskStatus(FlowTaskStatusConst.REJECT);
            ele.setFinishTime(DateUtil.date());
            ele.setOperator(operator);
          //  ele.setFlowParam(JsonUtil.obj2String(finalParam));
        }).collect(Collectors.toList());
        // 更新记录 -- List
        flowTaskService.saveList(tasks);

        //修改流程实例状态为关闭
        flowWork.setFlowWorkStatus(FlowWorkStatusConst.CLOSED);
        //流程挂起
        flowWork.setStatus(0);
        flowWorkService.updateWork(flowWork);
        return ResponseDTO.succMsg("驳回成功");
    }
}
